package room

import (
	"errors"
	"server/common"

	"github.com/mitchellh/mapstructure"
	"github.com/sirupsen/logrus"
)

// -------------------------------------------------------------------------------------------------
//
// -------------------------------------------------------------------------------------------------
func (s *RoomService) checkSubscribeReqData(data common.SFUStartSubscribeReqData) error {
	// Check if room ID provided
	if data.RoomId == "" {
		return errors.New("room ID is required in start subscribe request")
	}

	// Check if publish user ID provided
	if data.PubUserId == "" {
		return errors.New("user ID is required in start subscribe request")
	}

	// Check if subscribe user ID provided
	if data.UserId == "" {
		return errors.New("subscribe user ID is required in start subscribe request")
	}

	// Check media information
	if err := ValidateMediaInfo(data.Media); err != nil {
		return errors.New("invalid media information in start subscribe request")
	}

	// Check if room exists
	if !s.roomMgr.RoomExists(data.RoomId) {
		return errors.New("room does not exist")
	}

	// Check if publish user is in the room
	if !s.roomMgr.UserExists(data.RoomId, data.PubUserId) {
		return errors.New("publish user is not in the room")
	}

	// Check if subscribe user is in the room
	if !s.roomMgr.UserExists(data.RoomId, data.UserId) {
		return errors.New("subscribe user is not in the room")
	}

	// Check if media stream exists
	if !s.roomMgr.ProducerExists(data.RoomId, data.Media.MediaId) {
		return errors.New("media stream does not exist in the room")
	}

	// Check if consumer already exists
	if s.roomMgr.ConsumerExists(data.RoomId, data.UserId, data.Media.MediaId) {
		return errors.New("consumer already exists for the media stream in the room")
	}

	return nil
}

// -------------------------------------------------------------------------------------------------
//
// -------------------------------------------------------------------------------------------------
func (s *RoomService) sendStartSubscribeSuccessResponse(rid string, code int, msg string, connId string,
	data common.SFUStartSubscribeReqData, consumer *Consumer) {
	resMsg := common.Message{
		Cmd: common.SFU_START_SUBSCRIBE_RES,
		Rid: rid,
		Data: common.ResMsgData{
			Code: code,
			Msg:  msg,
			Data: common.SFUStartSubscribeResData{
				RoomId:        data.RoomId,
				UserId:        data.UserId,
				PubUserId:     data.PubUserId,
				ProducerId:    consumer.ProducerId,
				ConsumerId:    consumer.ConsumerId,
				Media:         data.Media,
				RtpParameters: consumer.RtpParameters,
				AppData:       map[string]interface{}{"producerId": data.PubUserId},
			},
		},
	}
	s.dispatcher.Dispatch(resMsg, s.serviceInfo, common.AccessServiceInfo, connId)
}

// -------------------------------------------------------------------------------------------------
//
// -------------------------------------------------------------------------------------------------
func (s *RoomService) sendStartSubscribeErrorResponse(rid string, code int, msg string, connId string,
	data common.SFUStartSubscribeReqData) {
	resMsg := common.Message{
		Cmd: common.SFU_START_SUBSCRIBE_RES,
		Rid: rid,
		Data: common.ResMsgData{
			Code: code,
			Msg:  msg,
			Data: common.SFUStartSubscribeResData{
				RoomId:    data.RoomId,
				UserId:    data.UserId,
				PubUserId: data.PubUserId,
				Media:     data.Media,
			},
		},
	}
	s.dispatcher.Dispatch(resMsg, s.serviceInfo, common.AccessServiceInfo, connId)
}

// -------------------------------------------------------------------------------------------------
//
// -------------------------------------------------------------------------------------------------
func (s *RoomService) handleStartSubscribeReq(msg common.Message, from common.ServiceInfo,
	connId string) error {
	LOG().WithFields(logrus.Fields{
		"msg":    common.ToJson(msg),
		"from":   from,
		"connId": connId,
	}).Info("Handling SFU Start Subscribe Request")

	var data common.SFUStartSubscribeReqData
	if err := mapstructure.Decode(msg.Data, &data); err != nil {
		return errors.New("failed to decode start subscribe request data: " + err.Error())
	}

	if err := s.checkSubscribeReqData(data); err != nil {
		LOG(msg.Rid).WithError(err).Error("Start subscribe request data validation failed")
		s.sendStartSubscribeErrorResponse(msg.Rid, 1, err.Error(), connId, data)
		return nil
	}

	consumer, err := s.roomMgr.CreateConsumer(msg.Rid, data)
	if err != nil {
		LOG(msg.Rid).WithError(err).Error("Failed to create consumer")
		s.sendStartSubscribeErrorResponse(msg.Rid, 1, "failed to create consumer", connId, data)
		return nil
	}

	s.sendStartSubscribeSuccessResponse(msg.Rid, 0, "success", connId, data, consumer)

	return nil
}
